/*****************************************************************************
 * plum_backtrace.h
 *
 * Copyright (C) 2020 Jeasonvor 1101627719@qq.com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 ****************************************************************************/
#ifndef __PLUM_BACKTRACE_H__
#define __PLUM_BACKTRACE_H__

/*****************************************************************************
 * Included Files
 ****************************************************************************/

/*****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

#if defined(__CC_ARM)
/* C stack block name, default is STACK */
#ifndef PLUM_CSTACK_BLOCK_NAME
#define PLUM_CSTACK_BLOCK_NAME STACK
#endif
/* code section name, default is ER_IROM1 */
#ifndef PLUM_CODE_SECTION_NAME
#define PLUM_CODE_SECTION_NAME ER_IROM1
#endif

#define PLUM_ELF_FILE_EXTENSION_NAME ".axf"

#elif defined(__ICCARM__)
/* C stack block name, default is 'CSTACK' */
#ifndef PLUM_CSTACK_BLOCK_NAME
#define PLUM_CSTACK_BLOCK_NAME "CSTACK"
#endif
/* code section name, default is '.text' */
#ifndef PLUM_CODE_SECTION_NAME
#define PLUM_CODE_SECTION_NAME ".text"
#endif

#define PLUM_ELF_FILE_EXTENSION_NAME ".out"

#elif defined(__GNUC__)
/* C stack block start address, defined on linker script file, default is
 * _sstack */
#ifndef PLUM_CSTACK_BLOCK_START
#define PLUM_CSTACK_BLOCK_START _sstack
#endif
/* C stack block end address, defined on linker script file, default is _estack
 */
#ifndef PLUM_CSTACK_BLOCK_END
#define PLUM_CSTACK_BLOCK_END _estack
#endif
/* code section start address, defined on linker script file, default is _stext
 */
#ifndef PLUM_CODE_SECTION_START
#define PLUM_CODE_SECTION_START _stext
#endif
/* code section end address, defined on linker script file, default is _etext */
#ifndef PLUM_CODE_SECTION_END
#define PLUM_CODE_SECTION_END _etext
#endif

#define PLUM_ELF_FILE_EXTENSION_NAME ".elf"
#else

#error "not supported compiler"
#endif

/* system handler control and state register */
#define PLUM_SYSHND_CTRL (*(volatile plum_u32*)(0xE000ED24u))
/* memory management fault status register */
#define PLUM_NVIC_MFSR (*(volatile plum_u8*)(0xE000ED28u))
/* bus fault status register */
#define PLUM_NVIC_BFSR (*(volatile plum_u8*)(0xE000ED29u))
/* usage fault status register */
#define PLUM_NVIC_UFSR (*(volatile plum_u16*)(0xE000ED2Au))
/* hard fault status register */
#define PLUM_NVIC_HFSR (*(volatile plum_u32*)(0xE000ED2Cu))
/* debug fault status register */
#define PLUM_NVIC_DFSR (*(volatile plum_u16*)(0xE000ED30u))
/* memory management fault address register */
#define PLUM_NVIC_MMAR (*(volatile plum_u32*)(0xE000ED34u))
/* bus fault manage address register */
#define PLUM_NVIC_BFAR (*(volatile plum_u32*)(0xE000ED38u))
/* auxiliary fault status register */
#define PLUM_NVIC_AFSR (*(volatile plum_u16*)(0xE000ED3Cu))

/*****************************************************************************
 * Public Types
 ****************************************************************************/

/**
 * Cortex-M fault registers
 */
struct plum_hard_fault_regs {
    struct {
        plum_u32 r0;   // Register R0
        plum_u32 r1;   // Register R1
        plum_u32 r2;   // Register R2
        plum_u32 r3;   // Register R3
        plum_u32 r12;  // Register R12
        plum_u32 lr;   // Link register
        plum_u32 pc;   // Program counter
        union {
            plum_u32 value;
            struct {
#if (PLUM_CPU_PLATFORM == CORTEX_M33)
                // Interrupt Program Status register (IPSR)
                plum_u32 IPSR : 9;
                // Execution Program Status register (EPSR)
                plum_u32 EPSR : 18;
                // Application Program Status register (APSR)
                plum_u32 APSR : 5;
#else
                // Interrupt Program Status register (IPSR)
                plum_u32 IPSR : 8;
                // Execution Program Status register (EPSR)
                plum_u32 EPSR : 19;
                // Application Program Status register (APSR)
                plum_u32 APSR : 5;
#endif
            } bits;
        } psr;  // Program status register.
    } saved;

    union {
        plum_u32 value;
        struct {
            // Read as 1 if memory management fault is active
            plum_u32 MEMFAULTACT : 1;
            // Read as 1 if bus fault exception is active
            plum_u32 BUSFAULTACT : 1;
#if (PLUM_CPU_PLATFORM == CORTEX_M33)
            // Read as 1 if hardfault is active
            plum_u32 HARDFAULTACT : 1;
#else
            plum_u32 UnusedBits1 : 1;
#endif
            // Read as 1 if usage fault exception is active
            plum_u32 USGFAULTACT : 1;
#if (PLUM_CPU_PLATFORM == CORTEX_M33)
            // Read as 1 if secure fault exception is active
            plum_u32 SECUREFAULTACT : 1;
            // Read as 1 if NMI exception is active
            plum_u32 NMIACT : 1;
            plum_u32 UnusedBits2 : 1;
#else
            plum_u32 UnusedBits2 : 3;
#endif
            // Read as 1 if SVC exception is active
            plum_u32 SVCALLACT : 1;
            // Read as 1 if debug monitor exception is active
            plum_u32 MONITORACT : 1;
            plum_u32 UnusedBits3 : 1;
            // Read as 1 if PendSV exception is active
            plum_u32 PENDSVACT : 1;
            // Read as 1 if SYSTICK exception is active
            plum_u32 SYSTICKACT : 1;
            // Usage fault pended; usage fault started but was replaced by a
            // higher-priority exception
            plum_u32 USGFAULTPENDED : 1;
            // Memory management fault pended; memory management fault started
            // but was replaced by a higher-priority exception
            plum_u32 MEMFAULTPENDED : 1;
            // Bus fault pended; bus fault handler was started but was replaced
            // by a higher-priority exception
            plum_u32 BUSFAULTPENDED : 1;
            // SVC pended; SVC was started but was replaced by a higher-priority
            // exception
            plum_u32 SVCALLPENDED : 1;
            // Memory management fault handler enable
            plum_u32 MEMFAULTENA : 1;
            // Bus fault handler enable
            plum_u32 BUSFAULTENA : 1;
            // Usage fault handler enable
            plum_u32 USGFAULTENA : 1;
#if (PLUM_CPU_PLATFORM == CORTEX_M33)
            // Secure fault handler enable
            plum_u32 SECUREFAULTENA : 1;
            // Secure fault pended; Secure fault handler was started but was
            // replaced by a higher-priority exception
            plum_u32 SECUREFAULTPENDED : 1;
            // Hard fault pended; Hard fault handler was started but was
            // replaced by a higher-priority exception
            plum_u32 HARDFAULTPENDED : 1;
#else
            // None
#endif
        } bits;
    } syshndctrl;  // System Handler Control and State Register (0xE000ED24)

    union {
        plum_u8 value;
        struct {
            // Instruction access violation
            plum_u8 IACCVIOL : 1;
            // Data access violation
            plum_u8 DACCVIOL : 1;
            plum_u8 UnusedBits : 1;
            // Unstacking error
            plum_u8 MUNSTKERR : 1;
            // Stacking error
            plum_u8 MSTKERR : 1;
            // Floating-point lazy state preservation (M4/M7)
            plum_u8 MLSPERR : 1;
            plum_u8 UnusedBits2 : 1;
            // Indicates the MMAR is valid
            plum_u8 MMARVALID : 1;
        } bits;
    } mfsr;         // Memory Management Fault Status Register (0xE000ED28)
    plum_u32 mmar;  // Memory Management Fault Address Register (0xE000ED34)

    union {
        plum_u8 value;
        struct {
            // Instruction access violation
            plum_u8 IBUSERR : 1;
            // Precise data access violation
            plum_u8 PRECISERR : 1;
            // Imprecise data access violation
            plum_u8 IMPREISERR : 1;
            // Unstacking error
            plum_u8 UNSTKERR : 1;
            // Stacking error
            plum_u8 STKERR : 1;
            // Floating-point lazy state preservation (M4/M7)
            plum_u8 LSPERR : 1;
            plum_u8 UnusedBits : 1;
            // Indicates BFAR is valid
            plum_u8 BFARVALID : 1;
        } bits;
    } bfsr;         // Bus Fault Status Register (0xE000ED29)
    plum_u32 bfar;  // Bus Fault Manage Address Register (0xE000ED38)

    union {
        plum_u16 value;
        struct {
            // Attempts to execute an undefined instruction
            plum_u16 UNDEFINSTR : 1;
            // Attempts to switch to an invalid state (e.g., ARM)
            plum_u16 INVSTATE : 1;
            // Attempts to do an exception with a bad value in the EXC_RETURN
            // number
            plum_u16 INVPC : 1;
            // Attempts to execute a coprocessor instruction
            plum_u16 NOCP : 1;
#if (PLUM_CPU_PLATFORM == CORTEX_M33)
            // Indicates a stack overflow error has occured
            plum_u16 STKOF : 1;
            plum_u16 UnusedBits : 3;
#else
            plum_u16 UnusedBits : 4;
#endif
            // Indicates that an unaligned access fault has taken place
            plum_u16 UNALIGNED : 1;
            // Indicates a divide by zero has taken place (can be set only if
            // DIV_0_TRP is set)
            plum_u16 DIVBYZERO0 : 1;
        } bits;
    } ufsr;  // Usage Fault Status Register (0xE000ED2A)

    union {
        plum_u32 value;
        struct {
            plum_u32 UnusedBits : 1;
            // Indicates hard fault is caused by failed vector fetch
            plum_u32 VECTBL : 1;
            plum_u32 UnusedBits2 : 28;
            // Indicates hard fault is taken because of bus fault/memory
            // management fault/usage fault
            plum_u32 FORCED : 1;
            // Indicates hard fault is triggered by debug event
            plum_u32 DEBUGEVT : 1;
        } bits;
    } hfsr;  // Hard Fault Status Register (0xE000ED2C)

    union {
        plum_u32 value;
        struct {
            // Halt requested in NVIC
            plum_u32 HALTED : 1;
            // BKPT instruction executed
            plum_u32 BKPT : 1;
            // DWT match occurred
            plum_u32 DWTTRAP : 1;
            // Vector fetch occurred
            plum_u32 VCATCH : 1;
            // EDBGRQ signal asserted
            plum_u32 EXTERNAL : 1;
        } bits;
    } dfsr;  // Debug Fault Status Register (0xE000ED30)

    // Auxiliary Fault Status Register (0xE000ED3C), Vendor controlled
    // (optional)
    plum_u32 afsr;
};

/*****************************************************************************
 * Public Data
 ****************************************************************************/

/****************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
/*****************************************************************************
 * Public Function Prototypes
 ****************************************************************************/

/****************************************************************************/
#ifdef __cplusplus
}
#endif
/****************************************************************************/
#endif /* __PLUM_BACKTRACE_H__ */
/****************************************************************************/
/*                                                                          */
/*  End of file.                                                            */
/*                                                                          */
/****************************************************************************/
